﻿
//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////

#include "CmdCreateGNodeId.h"
#include "IArc2d.h"
#include "IElement.h"
#include "OwnerPtr.h"
#include "IPolygon.h"
#include "Matrix4d.h"
#include "IDocument.h"
#include "ElementId.h"
#include "ISelection.h"
#include "IPolyCurve.h"
#include "IUiDocument.h"
#include "IDirectShape.h"
#include "GmBodyBuilder.h"
#include "IGenericElement.h"
#include "GcmpCommandState.h"
#include "IUserTransaction.h"
#include "IGraphicsBRepBody.h"
#include "IElementModelShape.h"
#include "IGraphicsNodeIdAsker.h"
#include "IGraphicsElementShape.h"
#include "IUiDocumentViewManager.h"
#include "IElementModelingOperations.h"
#include "GcmpElementModelingOperator.h"
#include "AlgorithmBodyTopologyOperate.h"
#include "GcmpBuiltInCategoryUniIdentities.h"

#include "GRepCommandIds.h"
#include "CommandRegister.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h" 

using namespace gcmp;
using namespace Sample;

// 每运行一次命令，下面数字会加一，创建的体块中有一个会创建数字对应面数的多边形
int TestBodyOperation::s_runCount = 3;

// 移动GNode
void Transform(IGraphicsNode* pGNode, int index)
{
    Matrix4d trf;
    trf.MakeTranslate(Vector3d(-3000.0 + index * -3000, -3000.0, 0.0));
    pGNode->Transform(trf);
}

bool Sample::TestBodyOperation::Execute(gcmp::IElement * pElement, gcmp::IGraphicsElementShape * pGraphicsElementShape)
{
    OwnerPtr<gcmp::IGraphicsNodeIdAsker> opGNodeIdAsker = CreateGraphicsNodeIdAsker(pElement);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(opGNodeIdAsker, L"opGNodeIdAsker为空", L"GDMP", L"2024-03-30");
    OwnerPtr<IPolygon> opPolygon = IPolygon::Create();
    std::vector<gcmp::Vector2d> points = { Vector2d(-1000, -1000), Vector2d(1000, -1000), Vector2d(1000, 1000), Vector2d(-1000, 1000), Vector2d(-1000, -1000) };
    OwnerPtr<IPolyCurve> opPolyCurve = IPolyCurve::Create(points);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(opPolyCurve, L"opPolyCurve为空", L"GDMP", L"2024-03-30");
    opPolygon->AddPolyCurveByClone(opPolyCurve.get());

    OwnerPtr<IPolygon> opCutPolygon = IPolygon::Create();
    std::vector<gcmp::Vector2d> cutPoints = { Vector2d(-1200, -600), Vector2d(0, -600), Vector2d(0, 600), Vector2d(-600, 600), Vector2d(-1200, -600) };
    OwnerPtr<IPolyCurve> opCutPolyCurve = IPolyCurve::Create(cutPoints);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(opCutPolyCurve, L"opCutPolyCurve为空", L"GDMP", L"2024-03-30");
    opCutPolygon->AddPolyCurveByClone(opCutPolyCurve.get());
    Coordinate3d coord;

    int index = 0;

    // 创建拉伸体，没有使用IGraphicsNodeIdAsker
    {
        std::vector<int> sketchIndexs = { 0, 1, 2, 3 };
        OwnerPtr<IBody> opGmIBody = GmBodyBuilder::CreateExtrudeBody(coord, opPolygon.get(), Vector3d::UnitZ, 0, 1000, sketchIndexs);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opGmIBody, L"opGmIBody为空", L"GDMP", L"2024-03-30");
        OwnerPtr<IGraphicsBRepBody> opGBody = IGraphicsBRepBody::Create(TransferOwnership(opGmIBody));
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opGBody, L"opGBody为空", L"GDMP", L"2024-03-30");
        Transform(opGBody.get(), index++);
        pGraphicsElementShape->AddChild(TransferOwnership(opGBody));
    }

    // 创建拉伸体，使用IGraphicsNodeIdAsker
    {
        std::vector<int> sketchIndexs = { 0, 1, 2, 3 };
        OwnerPtr<IBody> opGmIBody = GmBodyBuilder::CreateExtrudeBody(opGNodeIdAsker.get(), coord, opPolygon.get(), Vector3d::UnitZ, 0, 1000, sketchIndexs);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opGmIBody, L"opGmIBody为空", L"GDMP", L"2024-03-30");
        OwnerPtr<IGraphicsBRepBody> opGBody = IGraphicsBRepBody::Create(TransferOwnership(opGmIBody));
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opGBody, L"opGBody为空", L"GDMP", L"2024-03-30");
        Transform(opGBody.get(), index++);
        pGraphicsElementShape->AddChild(TransferOwnership(opGBody));
    }

    // 创建拉伸体，使用IGraphicsNodeIdAsker，改变草图线序号
    {
        std::vector<int> sketchIndexs = { 3, 2, 1, 0 };
        OwnerPtr<IBody> opGmIBody = GmBodyBuilder::CreateExtrudeBody(opGNodeIdAsker.get(), coord, opPolygon.get(), Vector3d::UnitZ, 0, 1000, sketchIndexs);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opGmIBody, L"opGmIBody为空", L"GDMP", L"2024-03-30");
        OwnerPtr<IGraphicsBRepBody> opGBody = IGraphicsBRepBody::Create(TransferOwnership(opGmIBody));
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opGBody, L"opGBody为空", L"GDMP", L"2024-03-30");
        Transform(opGBody.get(), index++);
        pGraphicsElementShape->AddChild(TransferOwnership(opGBody));
    }

    // 创建多边形拉伸体，多边形边数设置为s_runCount。这样可以查看节点标识的历史变化。
    {
        OwnerPtr<IPolygon> opPolygon = IPolygon::Create();
        OwnerPtr<IArc2d> opArc = IArc2d::Create(Vector2d::Zero, 1000, 0, Constants::MATH_2PI);
        std::vector<gcmp::Vector2d> points;
        std::vector<int> sketchIndexs;
        for (int i = 0; i <= s_runCount; i++)
        {
            double p = i * (opArc->GetLength() / s_runCount);
            points.emplace_back(opArc->GetPoint(p));
            sketchIndexs.emplace_back(i + 100);
        }
        OwnerPtr<IPolyCurve> opPolyCurve5 = IPolyCurve::Create(points);
        opPolygon->AddPolyCurveByClone(opPolyCurve5.get());
        OwnerPtr<IBody> opGmIBody = GmBodyBuilder::CreateExtrudeBody(opGNodeIdAsker.get(), coord, opPolygon.get(), Vector3d::UnitZ, 0, 1000, sketchIndexs);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opGmIBody, L"opGmIBody为空", L"GDMP", L"2024-03-30");
        OwnerPtr<IGraphicsBRepBody> opGBody = IGraphicsBRepBody::Create(TransferOwnership(opGmIBody));
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opGBody, L"opGBody为空", L"GDMP", L"2024-03-30");
        Transform(opGBody.get(), index++);
        pGraphicsElementShape->AddChild(TransferOwnership(opGBody));

        s_runCount += 1;
    }

    // 两个体块做布尔计算，没有使用IGraphicsNodeIdAsker
    {
        std::vector<int> sketchIndexs = { 20, 21, 22, 23 };
        std::vector<int> sketchIndexscut = { 200, 201, 202, 203 };
        OwnerPtr<IBody> opGmIBodyOrigin = GmBodyBuilder::CreateExtrudeBody(opGNodeIdAsker.get(), coord, opPolygon.get(), Vector3d::UnitZ, 0, 1000, sketchIndexs);
        OwnerPtr<IBody> opGmIBodyCut = GmBodyBuilder::CreateExtrudeBody(opGNodeIdAsker.get(), coord, opCutPolygon.get(), Vector3d::UnitZ, 0, 1000, sketchIndexscut);
        std::vector<BoolResultFaceSourceData> boolFaceDataList;
        std::vector<BoolResultEdgeSourceData> boolEdgeDataList;
        OwnerPtr<IBody> opGmIBody =
            AlgorithmBodyTopologyOperate::BoolOperate(opGmIBodyOrigin.get(), opGmIBodyCut.get(), BodyBooleanOperation::Substract, boolFaceDataList, boolEdgeDataList);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opGmIBody, L"opGmIBody为空", L"GDMP", L"2024-03-30");
        OwnerPtr<IGraphicsBRepBody> opGBody = IGraphicsBRepBody::Create(TransferOwnership(opGmIBody));
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opGBody, L"opGBody为空", L"GDMP", L"2024-03-30");
        Transform(opGBody.get(), index++);
        pGraphicsElementShape->AddChild(TransferOwnership(opGBody));
    }

    // 两个体块做布尔计算，使用IGraphicsNodeIdAsker
    {
        std::vector<int> sketchIndexs = { 30, 31, 32, 33 };
        std::vector<int> sketchIndexscut = { 300, 301, 302, 303 };
        OwnerPtr<IBody> opGmIBodyOrigin = GmBodyBuilder::CreateExtrudeBody(opGNodeIdAsker.get(), coord, opPolygon.get(), Vector3d::UnitZ, 0, 1000, sketchIndexs);
        OwnerPtr<IBody> opGmIBodyCut = GmBodyBuilder::CreateExtrudeBody(opGNodeIdAsker.get(), coord, opCutPolygon.get(), Vector3d::UnitZ, 0, 1000, sketchIndexscut);
        OwnerPtr<IGraphicsBRepBody> opGBodyOrigin = IGraphicsBRepBody::Create(TransferOwnership(opGmIBodyOrigin));
        OwnerPtr<IGraphicsBRepBody> opGBodyCut = IGraphicsBRepBody::Create(TransferOwnership(opGmIBodyCut));
        OwnerPtr<IGraphicsBRepBody> opGBody = 
            GcmpElementModelingOperator::CreateBoolBodyOperation(pElement, opGNodeIdAsker.get(), opGBodyOrigin.get(), opGBodyCut.get(), BooleanOperationTypes::Substract);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opGBody, L"opGBody为空", L"GDMP", L"2024-03-30");
        Transform(opGBody.get(), index++);
        pGraphicsElementShape->AddChild(TransferOwnership(opGBody));
    }

    return true;
}

REGISTER_COMMAND(CmdCreateGNodeId)

CmdCreateGNodeId::CmdCreateGNodeId()
    :CommandBase(ID_CMD_GREP_CREATE_GNODE_ID_ELEM)
{
}

bool CmdCreateGNodeId::IsEnabled() const
{
    return GcmpCommandState::IsInDocumentEnvironment();
}

bool CmdCreateGNodeId::IsVisible() const
{
    return GcmpCommandState::IsInDocumentEnvironment();
}

gcmp::OwnerPtr<gcmp::IAction> CmdCreateGNodeId::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiDocViewMgr, L"获取UI文档视图管理器失败",L"GDMP",L"2024-03-30");
    IUiDocument* pUiDoc = pUiDocViewMgr->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiDoc, L"获取UI文档失败",L"GDMP",L"2024-03-30");
    IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"获取文档失败",L"GDMP",L"2024-03-30");

    static ElementId sampleId = ElementId::InvalidID;
    IDirectShape* pDirectShape = nullptr;
    // 如果多次运行命令并且能找到原来的图元，那么会修改原图元。这样可以看到图元改变后节点标识系统跟踪节点标识
    if (sampleId.IsValid())
    {
        IGenericElement* pGElem = quick_cast<IGenericElement>(pDoc->GetElement(sampleId));
        if (pGElem)
        {
            pDirectShape = quick_cast<IDirectShape>(pGElem->GetExternalObject());
        }
    }

    OwnerPtr<IUserTransaction> opTransaction = IUserTransaction::Create(pDoc, L"添加GNode");
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opTransaction, L"opTransaction为空",L"GDMP",L"2024-03-30");

#pragma region 下面一部分一般在从IExternalObject用IGenericElement做扩展图元时，在构造函数或Create静态函数里创建
    // 如果图元没有创建，就创建一个，否则使用sampleId中缓存得到的图元
    if (pDirectShape == nullptr)
    {
        pDirectShape = IDirectShape::Create(pDoc, BuiltInCategoryUniIdentities::BICU_FORM);
        IElement* pOwnerElem = pDirectShape->GetOwnerElement();
        IGenericElement* pGenericElement = quick_cast<IGenericElement>(pOwnerElem);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMP",L"2024-03-30");

        // 创建建模运算器
        OwnerPtr<TestBodyOperation> opBodyOperation = NEW_AS_OWNER_PTR(TestBodyOperation);
        TestBodyOperation* pBodyOperation = opBodyOperation.get();

        // 创建建模组件，将建模运算器设置给建模组件
        OwnerPtr<IElementModelingOperations> opDefaultModelingOperation = IElementModelingOperations::CreateDefaultBehavior(pDoc, pOwnerElem->GetElementId());
        pGenericElement->SetElementModelingOperations(TransferOwnership(opDefaultModelingOperation));

        IElementModelingOperations* pModelingOperationHelper = pGenericElement->GetModelingOperationsFW();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pModelingOperationHelper, L"pModelingOperationHelper为空",L"GDMP",L"2024-03-30");
        pModelingOperationHelper->AddOperation(TransferOwnership(opBodyOperation));
    }
#pragma endregion

#pragma region 下面的运行可以在计算器里执行
    {
        IElement* pOwnerElem = pDirectShape->GetOwnerElement();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pOwnerElem, L"pOwnerElem为空",L"GDMP",L"2024-03-30");
        IGenericElement* pGenericElement = quick_cast<IGenericElement>(pOwnerElem);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMP",L"2024-03-30");
        sampleId = pGenericElement->GetElementId();

        gcmp::OwnerPtr<gcmp::IGraphicsElementShape> opResultGraphicsElementShape = gcmp::IGraphicsElementShape::Create(GraphicsRenderLayer::Model);

        // 获得建模组件并运行
        IElementModelingOperations* pDefaultModelingOperation = pGenericElement->GetModelingOperationsFW();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDefaultModelingOperation, L"pDefaultModelingOperation为空",L"GDMP",L"2024-03-30");
        pDefaultModelingOperation->Execute(pOwnerElem, opResultGraphicsElementShape.get());

        // 将建模组件运行更新的GRep设置给图元
        IElementModelShape* pElemModelShape = pOwnerElem->GetElementModelShape();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElemModelShape, L"pElemModelShape为空",L"GDMP",L"2024-03-30");
        pElemModelShape->SetGraphicsElementShape(TransferOwnership(opResultGraphicsElementShape));
    }
#pragma endregion
    opTransaction->Commit();
    return nullptr;
}

